package demo.axitdn;

import java.util.ArrayList;
import java.util.List;

import demo.axitdn.model.DemoModel;
import demo.axitdn.model.Model;
import demo.axitdn.physic.Accumulator;
import demo.axitdn.physic.CircularMotion;
import demo.axitdn.physic.FixedAxis;
import demo.axitdn.physic.GravityEffect;
import demo.axitdn.physic.LinearMotion;
import demo.axitdn.physic.SpringEffect;
import demo.axitdn.physic.State;
import demo.axitdn.physic.Vector3f;
import demo.axitdn.physic.ZeroForce;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class GameView extends SurfaceView {
	private Bitmap bmp;
	private SurfaceHolder holder;
	private GameLoopThread gameLoopThread;
	// Constants
	// 1m=30px;
	float x0 = 6;// m
	float y0 = 9;// m
	float v0 = 3.0f;// initial vel, m/s
	float vx0 = 100;
	float vy0 = 0;
	float angle = (float) (-Math.PI / 3.0f);
	double t;
	float dt = 0.009f;
	int nSteps = 100000;
	DemoModel demo;
	DemoModel demoR;
	DemoModel obj;
	DemoModel demo2;
	DemoModel center;
	List<Model> list;
	CircularMotion cm;
	LinearMotion lm;
	FixedAxis fa;

	/** Set up for the algorithm. **/
	public void init() {
		t = 0.0f;
		demo = new DemoModel(x0, y0, 3f, angle, t, 15);
		obj = new DemoModel(x0, y0, 0, angle, t, 15);
		demo.getState().velocity = new Vector3f(9, 0, 0);

		cm = new CircularMotion(demo.getState().position,
				demo.getState().velocity, new Vector3f(x0, y0, 0), 5f,
				(float) Math.PI / 3, dt);
		demo.setForce(cm);
		demo2=new DemoModel(new Vector3f(1,7,0),new Vector3f());
		lm=new LinearMotion(new Vector3f(-0.01f,0,0), new Vector3f(9, 0, 0));
		demo2.setForce(lm);

		demoR=new DemoModel(new Vector3f(1,7,0),new Vector3f());
		fa=new FixedAxis(demoR.getState(), lm, new Vector3f(x0, y0, 0), 5);
		demoR.setForce(fa);
		
		center = new DemoModel(x0, y0, 0, angle, t, 1);
		center.setForce(new ZeroForce());
		list = new ArrayList<Model>();
		list.add(demo);
		list.add(demo2);
		list.add(demoR);
		list.add(center);
		list.add(obj);
	} // init

	public GameView(Context context) {
		super(context);
		init();
		gameLoopThread = new GameLoopThread(this);
		holder = getHolder();
		holder.addCallback(new SurfaceHolder.Callback() {

			@Override
			public void surfaceDestroyed(SurfaceHolder holder) {
				boolean retry = true;
				gameLoopThread.setRunning(false);
				while (retry) {
					try {
						gameLoopThread.join();
						retry = false;
					} catch (InterruptedException e) {
					}
				}
			}

			@Override
			public void surfaceCreated(SurfaceHolder holder) {
				gameLoopThread.setRunning(true);
				gameLoopThread.start();
			}

			@Override
			public void surfaceChanged(SurfaceHolder holder, int format,
					int width, int height) {
			}
		});
		bmp = BitmapFactory.decodeResource(getResources(),
				R.drawable.ic_launcher);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		// canvas.drawColor(Color.GREEN);
		canvas.drawColor(Color.BLACK);
		Paint p = new Paint();
		p.setColor(Color.GREEN);

		drawVector(canvas, demo.getState().position, demo.getState().velocity);
		drawVector(canvas, Vector3f.ZERO, demo.getState().velocity);
		drawVector(canvas, center.getState().position, cm.getR());
		drawVectorInfo(canvas, 2, 10, cm.getR());

		for (Model m : list) {
			m.onDraw(canvas);
		}
	}

	private void drawVectorInfo(Canvas c, float x, float y, Vector3f v) {
		Paint p = new Paint();
		p.setColor(Color.YELLOW);
		c.drawText(v.toString(), x, y, p);
	}

	private void drawVector(Canvas c, Vector3f o, Vector3f v) {
		Paint p = new Paint();
		p.setColor(Color.CYAN);
		Vector3f vv = (Vector3f) v.clone();
		vv = vv.addLocal(o);
		c.drawLine(o.x * 30, o.y * 30, vv.x * 30, vv.y * 30, p);
	}

	public void onUpdate(Accumulator acc) {
		for (Model m : list) {
			m.onUpdate(t);
		}

		while (acc.accumulator >= dt) {
			acc.accumulator -= dt;

			for (Model m : list) {
				m.integrate(t, dt);
			}

			t += dt;
			if (t == Double.MAX_VALUE) {
				t = 0;
			}
		}
		double alpha = (acc.accumulator / dt);
		for (Model m : list) {
			m.interpolate(alpha);
		}

	}

	@Override
	public boolean onTouchEvent(MotionEvent evt) {
		// TODO Auto-generated method stub
		int x = (int) evt.getX();
		int y = (int) evt.getY();
		fireTouchEvent(evt);
		switch (evt.getAction()) {
		case MotionEvent.ACTION_DOWN:
			invalidate();
			break;
		case MotionEvent.ACTION_MOVE:
			break;
		case MotionEvent.ACTION_UP:
			break;
		}
		return true;
	}

	private void fireTouchEvent(MotionEvent evt) {
		for (Model m : list) {
			m.onTouchEvent(evt);
		}
	}

}
